﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Windows.Forms;

namespace CashCommon
{
    /// <summary>
    /// Класс предназначен для сохранения пользовательских настроек различных частей программы
	/// </summary>
	/// <remarks>
	/// Класс не создается явно, для получения экземпляра класса необходимо воспользоваться статическим 
    /// методом Current()
	/// </remarks>
    [Serializable]
    public class Adjustment : ISerializable
    {
	
	#region Cтатические методы для работы с классом
		
		public static Adjustment Default
        {
			get
			{
				return _adjustment;
			}
        }
        public static void Save()
        { 
            IFormatter formatter = new BinaryFormatter();

			using (Stream stream = new FileStream(AdjustmentFile, FileMode.Create, FileAccess.Write, FileShare.None))
            {
				formatter.Serialize(stream, Adjustment.Default);
            }
        }
        public static void Load()
        {
			if (!Directory.Exists(Path.GetDirectoryName(AdjustmentFile)))
				Directory.CreateDirectory(Path.GetDirectoryName(AdjustmentFile));

			using (Stream stream = new FileStream(AdjustmentFile, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read))
            {
                IFormatter formatter = new BinaryFormatter();
				try
				{
					_adjustment = (Adjustment)formatter.Deserialize(stream);
				}
				catch 
				{
					_adjustment = new Adjustment();
				}
				
            }
		}
        public static void Reload()
        {
            Adjustment.Save();
            Adjustment.Load();
        }
		public static string AppDir = Path.GetDirectoryName(Application.ExecutablePath);
		public static string AdjustmentFile;
		public static int DefaultCount = 10;

	#endregion

	#region Properties

		/// <summary>
		/// Количество записей отображаемых в запросах из таблицы Cash
		/// </summary>
		/// <remarks>Количество записей не может быть более 50 и менее 1. 
		/// Ограничение отслеживается автоматически, при попытке присвоить значение не находящееся в указанном интервале, сохраняется 
		/// минимально возможное значение, если диапазаон выходит за рамки нижней границы и максимально возможное, если значение 
		/// выходит за границы верхнего диапазона</remarks>
        public int CountRecordCash
        {
            get { return _countRecordCash; }
            set { _countRecordCash = value;}
        }

		/// <summary>
		/// Количество записей отображаемых в списках доступа
		/// </summary>
		/// <remarks>Количество записей не может быть более 20 и менее 1. 
		/// Ограничение отслеживается автоматически, при попытке присвоить значение не находящееся в указанном интервале, сохраняется 
		/// минимально возможное значение, если диапазаон выходит за рамки нижней границы и максимально возможное, если значение 
		/// выходит за границы верхнего диапазона</remarks>
		public int CountRowComboBox
		{
			get { return this._countRowComboBox; }
			set
			{
                if ((value > 20) || (value < 1))
                    this._countRowComboBox = 20;
                else
                    this._countRowComboBox = value;
			}
		}

        /// <summary>
        /// Список серверов
        /// </summary>
		public ComboBoxItemList ServersList { get { return this._serversList; } }

        /// <summary>
        /// Настройки сетки списка чеков
        /// </summary>
        public GridColumnsList RegisterGrid { get { return this._registerGrid; } }

        /// <summary>
        /// Настройки сетки списка счетов
        /// </summary>
        public GridColumnsList CashGrid { get { return this._cashGrid; } }
	
	#endregion

	#region Сериализация

		protected Adjustment(SerializationInfo info, StreamingContext context)
        {

            this.CountRecordCash = info.GetInt32("CountRecordCash"); 
			this.CountRowComboBox = info.GetInt32("CountRowComboBox");
            this._serversList = (ComboBoxItemList)info.GetValue("ServerList", _serversList.GetType());
            this._registerGrid = (GridColumnsList)info.GetValue("RegisterGrid", _registerGrid.GetType());
            this._cashGrid = (GridColumnsList)info.GetValue("CashGrid", _cashGrid.GetType());
        }
        
		[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("CountRecordCash", this.CountRecordCash);
			info.AddValue("CountRowComboBox", this._countRowComboBox);
            info.AddValue("ServerList", this._serversList);
            info.AddValue("RegisterGrid", this._registerGrid);
            info.AddValue("CashGrid", this._cashGrid);
		}

		#endregion

    #region Поля сериалзиации
        
    private int _countRecordCash = 1000;
	private int _countRowComboBox = 10;
    private ComboBoxItemList _serversList = new ComboBoxItemList();
    private GridColumnsList _registerGrid = new GridColumnsList();
    private GridColumnsList _cashGrid = new GridColumnsList();

    #endregion

    private static Adjustment _adjustment;
	private Adjustment() { }

	}

    [Serializable]
    public class Config : ISerializable
    {

        #region Cтатические методы для работы с классом

        public static Config Default
        {
            get
            {
                return _config;
            }
        }
        public static void Save()
        {
            IFormatter formatter = new BinaryFormatter();

            using (Stream stream = new FileStream(_path, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                formatter.Serialize(stream, Config.Default);
            }
        }
        public static void Reload()
        {
            using (Stream stream = new FileStream(_path, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read))
            {
                IFormatter formatter = new BinaryFormatter();
                try
                {
                    _config = (Config)formatter.Deserialize(stream);
                }
                catch
                {
                    _config = new Config();
                }

            }
        }
        
        private static string _path = String.Format("{0}\\{1}", Path.GetDirectoryName(Application.ExecutablePath), "Config.adj");

        #endregion

        #region Properties

        public ComboBoxItemList ServersList { get { return this._serversList; } }
        public ComboBoxItemList CatalogsList { get { return this._catalogsList; } }
        public int CurrentAuth { get { return this._currentAuth; } set { this._currentAuth = value; } }
        public string CurrentServer { get { return this._currentServer; } set { this._currentServer = value; } }
        public string CurrentCatalog { get { return this._currentCatalog; } set { this._currentCatalog = value; } }

        #endregion

        #region Сериализация

        protected Config(SerializationInfo info, StreamingContext context)
        {
            this._serversList = (ComboBoxItemList)info.GetValue("ServersList", _serversList.GetType());
            this._catalogsList = (ComboBoxItemList)info.GetValue("CatalogsList", _catalogsList.GetType());
            this._currentAuth = info.GetInt32("CurrentAuth");
            this._currentServer = info.GetString("CurrentServer");
            this._currentCatalog = info.GetString("CurrentCatalog");
        }

        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("ServersList", this._serversList);
            info.AddValue("CatalogsList", this._catalogsList);
            info.AddValue("CurrentAuth", this._currentAuth);
            info.AddValue("CurrentServer", this._currentServer);
            info.AddValue("CurrentCatalog", this._currentCatalog);
	    }

        #endregion

        #region Private


        // Переменные для свойств
        private ComboBoxItemList _serversList = new ComboBoxItemList();
        private ComboBoxItemList _catalogsList = new ComboBoxItemList();
        private int _currentAuth = 0;
        private string _currentServer = "";
        private string _currentCatalog = "";

        private static Config _config;
        private Config() { }

        #endregion
    }
	
    #region Cериализации элементов списка

    [Serializable]
	public class ComboBoxItemList
	{
        public void AddRange(ComboBoxItem[] cbItems)
        {
            foreach (ComboBoxItem item in cbItems)
            {
                AddOneElement(item);   
            }
        }
        public void Add(ComboBoxItem cbItem)
		{
            AddOneElement(cbItem);
		}

        private void AddOneElement(ComboBoxItem cbItem)
        {
            ComboBoxItem cb = _cbList.Where(i => i.ID == cbItem.ID && i.Name.ToUpper() == cbItem.Name.ToUpper()).
                         ElementAtOrDefault(0);
            if (cb != null)
                cb.Weight++;
            else
            {
                int countRow = Adjustment.Default == null ? Defaults.RowCount : Adjustment.Default.CountRowComboBox;
                if (countRow <= _cbList.Count)
                    _cbList.Remove(_cbList.Where(i => i.Weight == _cbList.Min(ii => ii.Weight)).ElementAtOrDefault(0));
                _cbList.Add(cbItem);
            }
        }
		public void Clear()
		{
			_cbList.Clear();
		}
		public ComboBoxItem Selected { get; set; }
		public List<ComboBoxItem> Items { get { return this._cbList; } }

		//Private

		private List<ComboBoxItem> _cbList = new List<ComboBoxItem>();
	}

	[Serializable]
	public class ComboBoxItem
	{
		//Constructors
		public ComboBoxItem(int id) { this._id = id; }
		public ComboBoxItem(string shortName) { this._shortName = shortName; }
		public ComboBoxItem(int id, string shortName) { this._id = id; this._shortName = shortName; }
        public ComboBoxItem(int id, string shortName, double weight) { this._id = id; this._shortName = shortName; Weight = weight; }

		//Properties
		public int ID { get { return this._id; } }
		public string Name { get { return this._shortName; } }
		public double Weight { get; set; }

		//Private
		private int _id = 0;
		private string _shortName = "";
	}

	#endregion

	#region Сериализация фильтров

	[Serializable]
	public class FiltersList
	{
		public void Add(FilterItem filterItem)
		{
			_filterList.Add(filterItem);
		}
		public void Clear()
		{
			_filterList.Clear();
		}
		public FilterItem this[string name] 
		{
			get { return this._filterList.Where(i => i.Name == name).ElementAtOrDefault(0); }
		}
		public List<FilterItem> Items { get { return this._filterList; } }

		//Private
		private List<FilterItem> _filterList = new List<FilterItem>();
	}

	[Serializable]
	public class FilterItem
	{
		public FilterItem(string name, SqlSwitch swth, List<string> captions)
		{
			this.Name = name;
			this.Condition = swth.Condition.Select(x => x).ToList();
			this.SqlCaptions = captions.Select(x => x).ToList();
		}

		//Properties
		public string Name { get; set; }
		public List<string> SqlCaptions { get; set; }
		public List<SqlCase> Condition { get; set; }

	}

	#endregion
    
    #region Сериализация dataGrid
    
    [Serializable]
    public class GridColumnsList
    {
        public void AddRange(GridColumn[] columnItem)
        {
            foreach (var item in columnItem)
            {
                Add(item);
            }
        }
        public void Add(GridColumn columnItem)
        {
            _columnList.Add(columnItem);
        }
        public void Clear()
        {
            _columnList.Clear();
        }
        public GridColumn this[string name]
        {
            get { return this._columnList.Where(i => i.Name == name).ElementAtOrDefault(0); }
        }
        public List<GridColumn> Items { get { return this._columnList; } }
        public string SortedColumn { get; set; }
        public bool SortedAsc { get; set; }

        //Private
        private List<GridColumn> _columnList = new List<GridColumn>();
    
    }

    [Serializable]
    public class GridColumn
    {
        public GridColumn(string name, string caption, int position, int width)
        {
            this.Name = name;
            this.Caption = caption;
            this.Position = position;
            this.Width = width;
        }

        //Properties
        public string Name { get; set; }
        public string Caption { get; set; }
        public int Position { get; set; }
        public int Width { get; set; }
    }
    #endregion
}
